package Parsers::ReSchedule;
use strict;
use Data::Dump qw[ dump ];
use Parsers;
use Win32::OLE;

use vars qw[@Expected_keys];
=pod
@Expected_keys Specifies columns order and number. 
    Use:
    Parsers::ReSchedule->set_expected_keys(@keys)  
    to define expected keys before call of the constructor new. 

=cut
@Expected_keys = ();

sub set_expected_keys {
    my ($class, @keys) = @_;
    @Expected_keys = @keys;
}

use constant MAX_ALLOWED_ROWS_TO_READ => 300;

sub new {
    my ( $class, $abs_file_path, $password ) = @_;
    if (@Expected_keys == 0) {
        die msg "Parsers::ReSchedule \@Expected_keys is empty. Define it first.";
    }

    my $data = {};
    my $xl = Win32::OLE->new("Excel.Application");
    # $abs_file_path
    
    $xl->{Visible} = 0;
    my $wb = $xl->Workbooks->Open($abs_file_path) 
             or die msg "Unable to open $abs_file_path"; 

    $data->{'excel'}    = $xl;
    $data->{'workbook'} = $wb;
    bless $data, $class;
};

sub prepare {
    my ($this, $start_row, $statement) = @_;
    my %data  = %$this;
    my $class = ref $this;
    unless ( $this->_check_data_hash($statement) ) {
        die msg "Incorrect statement:\n" . dump($statement);
    }
    $data{'statement'}      = $statement;
    $data{'data_start_row'} = $start_row;
    $data{'workbook'}       = $this->{'workbook'};
    return bless \%data, $class;
}

sub execute {
    my ($this) = @_;
    if (!$this->{'statement'}) {
        die msg "Statement not specified. Use function prepare to prepare the valid statement";
    }
    my @data;
    my $st = $this->{'statement'};
    my $data_start = $this->{'data_start_row'};
    my $lng_col    = $st->{'lang'};

    # Read while Lang not empty 
    my $i = $data_start;

    while ( $i <  MAX_ALLOWED_ROWS_TO_READ) {
        my $lng = $this->read($i, $lng_col);
        last if $lng =~ /^\s*$/;
        my $row_data = {};
        foreach my $key (@Expected_keys) {
            my $row = $i;
            my $col = $st->{$key};
            $row_data->{$key} = $this->read($row, $col);
        }
        push @data, $row_data;
        $i++;
    }

    $this->{'rows_data'} = \@data;
}

sub next {
    my ( $this ) = @_;
    return shift @{$this->{'rows_data'}};
}


sub read {     # 1   # A 
    my ($this, $row, $col) = @_;
    my $sheet = $this->{'workbook'}->{'ActiveSheet'};
    my $value = $sheet->Cells($row, $col)->{'Value'};
    return $value;
}

sub _check_data_hash {
    my ($this, $data) = @_;

    my @not_found_keys;
    foreach my $exp_key (@Expected_keys) {
        if ( !$data->{$exp_key} ) {
            warn msg "Expected key $exp_key not specified";
            push @not_found_keys, $exp_key;
        }
    }
    my $failed = @not_found_keys;
    return !$failed;
}


sub DESTROY {
    my $this = shift;
    if ( $this->{'excel'} ) {
        $this->{'excel'}->Quit();
        $this->{'excel'} = undef;
    }

}

1;
=pod 
http://msdn.microsoft.com/en-us/library/bb179167.aspx





=cut